/// ml278
/// Copyright (C) 2008 Bjørn Øivind Bjørnsen, Aleksander Gjermundsen, Knut Andre Tidemann, Thomas Hansen
///
/// This program is free software; you can redistribute it and/or
/// modify it under the terms of the GNU General Public License
/// as published by the Free Software Foundation; either version 2
/// of the License, or (at your option) any later version.
///
/// This program is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
/// GNU General Public License for more details.
///
/// You should have received a copy of the GNU General Public License
/// along with this program; if not, write to the Free Software
/// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

uniform sampler2D sLookup;
uniform sampler2D sGroundPack;

varying float fAlt;
varying float fSlope;

/// This function evaluates the mipmap LOD level for a 2D texture using the given texture coordinates
/// and texture size (in pixels)
/// curtesy of http://www.gamedev.net/community/forums/mod/journal/journal.asp?jn=263350&reply_id=3198944
float mipmapLevel(vec2 uv, vec2 textureSize)
{
    vec2 dx = dFdx(uv * textureSize.x);
    vec2 dy = dFdy(uv * textureSize.y);
    float d = max(dot(dx, dx), dot(dy, dy));
    return 0.5 * log2(d);
}

vec3 calculateTexturePackMipWrapped(const in vec2 uv, const in vec4 packFactors, const in vec2 tile)
{
   vec3 uvw0;
   /// estimate mipmap/LOD level
   float lod = mipmapLevel(uv, vec2(packFactors.z));
   lod = clamp(lod, 0.0, packFactors.w);
   uvw0.z = lod;
   
   /// get width/height of the whole pack texture for the current lod level
   float size = pow(2.0, packFactors.w - lod);
   float sizex = size / packFactors.x; // width in pixels
   float sizey = size / packFactors.y; // height in pixels

   /// perform tiling
   uvw0 = fract(uvw0);

   /// tweak pixels for correct bilinear filtering, and add offset for the wanted tile
   uvw0.x = uvw0.x * ((sizex * packFactors.x - 1.0) / sizex) + 0.5 / sizex + packFactors.x * tile.x;
   uvw0.y = uvw0.y * ((sizey * packFactors.y - 1.0) / sizey) + 0.5 / sizey + packFactors.y * tile.y;
   
   return(uvw0);
}

void main()
{
   const vec2 diffPackFactors = vec2(0.25, 0.25);
   vec2 uv = vec2(gl_TexCoord[0]);
   const int nbTiles = int(1.0 / diffPackFactors.x);
   
   // TODO: fBm noise texture
   //float slope = fSlope + (noise1(fSlope) * 0.001);
   //float alt = fAlt + (noise1(fAlt) * 0.001);
   
   vec4 terrainType = texture2D(sLookup, vec2(fSlope, fAlt));
   // IDs now embedded in lut-table
   //int id0 = int(terrainType.x * 16.0);
   //vec2 offset0 = vec2(int(mod(float(id0), float(nbTiles))), id0 / nbTiles);
   vec2 offset0 = terrainType.yz;
   
   vec4 packFactors = vec4(diffPackFactors.xy, 512.0, 9.0);
   
   vec3 uvw0 = calculateTexturePackMipWrapped(uv, packFactors, offset0);
   
   vec4 diffuse = texture2DLod(sGroundPack, uvw0.xy, uvw0.z);
   //vec4 diffuse = texture2D(sGroundPack, uvw0.xy);
   //vec4 diffuse = vec4(terrainType.x, terrainType.x, terrainType.x, 1.0);

   gl_FragColor = diffuse;
}
